/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include "spidev.h"
#include <string.h>
#define MAXRLEN 18 
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <netdb.h>  

int beep_ionum=0x6C; //PD12
/////////////////////////////////////////////////////////////////////
//MF522命令字
/////////////////////////////////////////////////////////////////////
#define PCD_IDLE              0x00               //取消当前命令
#define PCD_AUTHENT           0x0E               //验证密钥
#define PCD_RECEIVE           0x08               //接收数据
#define PCD_TRANSMIT          0x04               //发送数据
#define PCD_TRANSCEIVE        0x0C               //发送并接收数据
#define PCD_RESETPHASE        0x0F               //复位
#define PCD_CALCCRC           0x03               //CRC计算

/////////////////////////////////////////////////////////////////////
//Mifare_One卡片命令字
/////////////////////////////////////////////////////////////////////
#define PICC_REQIDL           0x26               //寻天线区内未进入休眠状态
#define PICC_REQALL           0x52               //寻天线区内全部卡
#define PICC_ANTICOLL1        0x93               //防冲撞
#define PICC_ANTICOLL2        0x95               //防冲撞
#define PICC_AUTHENT1A        0x60               //验证A密钥
#define PICC_AUTHENT1B        0x61               //验证B密钥
#define PICC_READ             0x30               //读块
#define PICC_WRITE            0xA0               //写块
#define PICC_DECREMENT        0xC0               //扣款
#define PICC_INCREMENT        0xC1               //充值
#define PICC_RESTORE          0xC2               //调块数据到缓冲区
#define PICC_TRANSFER         0xB0               //保存缓冲区中数据
#define PICC_HALT             0x50               //休眠


//-------------------------异常类型--------------------//
#define PICCERR_NULL          0x01               //正常
#define PICCERR_NOCARD        0x02               //检测卡
#define PICCERR_ANTI          0x03               //防冲突异常
#define PICCERR_SELECT        0x04               //选卡异常
#define PICCERR_PSW           0x05               //密码错误
#define PICCERR_DATA          0x06               //数据错误
/////////////////////////////////////////////////////////////////////
//MF522 FIFO长度定义
/////////////////////////////////////////////////////////////////////
#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte

/////////////////////////////////////////////////////////////////////
//MF522寄存器定义
/////////////////////////////////////////////////////////////////////
// PAGE 0
#define     RFU00                 0x00    
#define     CommandReg            0x01    
#define     ComIEnReg             0x02    
#define     DivlEnReg             0x03    
#define     ComIrqReg             0x04    
#define     DivIrqReg             0x05
#define     ErrorReg              0x06    
#define     Status1Reg            0x07    
#define     Status2Reg            0x08    
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     RFU0F                 0x0F
// PAGE 1     
#define     RFU10                 0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     RFU1A                 0x1A
#define     RFU1B                 0x1B
#define     MifareReg             0x1C
#define     RFU1D                 0x1D
#define     RFU1E                 0x1E
#define     SerialSpeedReg        0x1F
// PAGE 2    
#define     RFU20                 0x20  
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     RFU23                 0x23
#define     ModWidthReg           0x24
#define     RFU25                 0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsCfgReg            0x28
#define     ModGsCfgReg           0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
// PAGE 3      
#define     RFU30                 0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39  
#define     TestDAC2Reg           0x3A   
#define     TestADCReg            0x3B   
#define     RFU3C                 0x3C   
#define     RFU3D                 0x3D   
#define     RFU3E                 0x3E   
#define     RFU3F		  0x3F

/////////////////////////////////////////////////////////////////////
//和MF522通讯时返回的错误代码
/////////////////////////////////////////////////////////////////////
#define MI_OK                          0
#define MI_NOTAGERR                    (-1)
#define MI_ERR                         (-2)

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
void Sleep(int ms)  
{  
    usleep(ms*1000);
}
static void pabort(const char *s)
{
	perror(s);
	abort();
}

static const char *device = "/dev/spidev0.0";
static int fd;
static uint32_t mode = 2;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;

static void WriteRawRC(uint8_t Address,uint8_t value)
{
	int ret;
	uint8_t tx[10];
	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = 2,
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};
	uint8_t BAddress;

	BAddress = ((Address<<1)&0x7E);

	tx[0] = BAddress;
	tx[1] = value;
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");

	//tx[0] = value;
	//ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	//if (ret < 1)
	//	pabort("can't send spi message");

	//printf("Send:0x%-02X,Send:0x%-02X\n",Address,value);
}
static uint8_t ReadRawRC(uint8_t Address)
{
	int ret;
	uint8_t tx[10];
	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = 2,
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};
	uint8_t BAddress;

	BAddress =((Address<<1)&0x7E)|0x80;

	tx[0] = BAddress;
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");

	//tx[0] = 0;
	//ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	//if (ret < 1)
	//	pabort("can't send spi message");
	//printf("Send:0x%-02X,Recv:0x%-02X\n",Address,rx[1]);
	return rx[1];
}
void SetBitMask(unsigned char reg,unsigned char mask)  
{
    char tmp = 0x0;
    tmp = ReadRawRC(reg);
    WriteRawRC(reg,tmp | mask);  
}
void ClearBitMask(unsigned char reg,unsigned char mask)  
{
    char tmp = 0x0;
    tmp = ReadRawRC(reg);
    WriteRawRC(reg, tmp & ~mask);  
} 
char PcdReset(void)
{
    WriteRawRC(CommandReg,PCD_RESETPHASE);
    WriteRawRC(ModeReg,0x3D);           
    WriteRawRC(TReloadRegL,30);           
    WriteRawRC(TReloadRegH,0);
    WriteRawRC(TModeReg,0x8D);
    WriteRawRC(TPrescalerReg,0x3E);
    WriteRawRC(TxAutoReg,0x40);     
    return MI_OK;
}
//==================================================================================================
//| 函数名称 | CalulateCRC
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 用MF522计算CRC16函数
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | 
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData)
{
    unsigned char i,n;
    ClearBitMask(DivIrqReg,0x04);
    WriteRawRC(CommandReg,PCD_IDLE);
    SetBitMask(FIFOLevelReg,0x80);
    for (i=0; i<len; i++)
    {   WriteRawRC(FIFODataReg, *(pIndata+i));   }
    WriteRawRC(CommandReg, PCD_CALCCRC);
    i = 0xFF;
    do 
    {
        n = ReadRawRC(DivIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x04));
    pOutData[0] = ReadRawRC(CRCResultRegL);
    pOutData[1] = ReadRawRC(CRCResultRegM);
}
//==================================================================================================
//| 函数名称 | PcdAntennaOn
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 启动天线  函数,每次启动或关闭天险发射之间应至少有1ms的间隔
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | 
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
void PcdAntennaOn()
{
    unsigned char i;
    i = ReadRawRC(TxControlReg);
    if (!(i & 0x03))
    {
        SetBitMask(TxControlReg, 0x03);
	//printf("Ant On!\n");
    }
}
//==================================================================================================
//| 函数名称 | PcdAntennaOff
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 关闭天线  函数
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | 
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
void PcdAntennaOff()
{
    ClearBitMask(TxControlReg, 0x03);
}
//==================================================================================================
//| 函数名称 | M500PcdConfigISOType
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 设置RC522的工作方式  函数 
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | 
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
signed char M500PcdConfigISOType(unsigned char type)
{
   if (type == 'A')                     //ISO14443_A
   { 
       ClearBitMask(Status2Reg,0x08);
       WriteRawRC(ModeReg,0x3D);//3F
       WriteRawRC(RxSelReg,0x86);//84
       WriteRawRC(RFCfgReg,0x7F);   //4F
   	   WriteRawRC(TReloadRegL,30);//tmoLength);// TReloadVal = 'h6a =tmoLength(dec) 
	   WriteRawRC(TReloadRegH,0);
       WriteRawRC(TModeReg,0x8D);
	   WriteRawRC(TPrescalerReg,0x3E);
	 
	   Sleep(5);
       PcdAntennaOn();
   }
   else
   { 
	  return -1; 
   }

   return MI_OK;
}
//==================================================================================================
//| 函数名称 | PcdComMF522
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 |  RC522和ISO14443卡通讯  函数
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 |  Command[IN]:RC522命令字
//|          |  pInData[IN]:通过RC522发送到卡片的数据
//|          |  InLenByte[IN]:发送数据的字节长度
//|          |  pOutData[OUT]:接收到的卡片返回数据
//|          |  *pOutLenBit[OUT]:返回数据的位长度
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
char PcdComMF522(unsigned char Command, 
                 unsigned char *pInData, 
                 unsigned char InLenByte,
                 unsigned char *pOutData, 
                 unsigned int  *pOutLenBit)
{
    signed char status = MI_ERR;
    unsigned char irqEn   = 0x00;
    unsigned char waitFor = 0x00;
    unsigned char lastBits;
    unsigned char n;
    unsigned int i;
    switch (Command)
    {
        case PCD_AUTHENT:
			irqEn   = 0x12;
			waitFor = 0x10;
			break;
		case PCD_TRANSCEIVE:
			irqEn   = 0x77;
			waitFor = 0x30;
			break;
		default:
			break;
    }
   
    WriteRawRC(ComIEnReg,irqEn|0x80);
    ClearBitMask(ComIrqReg,0x80);
    WriteRawRC(CommandReg,PCD_IDLE);
    SetBitMask(FIFOLevelReg,0x80);
    
    for (i=0; i<InLenByte; i++)
    {   
		WriteRawRC(FIFODataReg, pInData[i]);    
	}
    WriteRawRC(CommandReg, Command);
   
    if (Command == PCD_TRANSCEIVE)
    {    
		SetBitMask(BitFramingReg,0x80);  
	}
    
	i = 6000;
    do 
    {
        n = ReadRawRC(ComIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x01) && !(n&waitFor));
    ClearBitMask(BitFramingReg,0x80);

    if (i!=0)
    {    
        if(!(ReadRawRC(ErrorReg)&0x1B))
        {
            status = MI_OK;
            if (n & irqEn & 0x01)
            {   status = MI_NOTAGERR;   }
            if (Command == PCD_TRANSCEIVE)
            {
               	n = ReadRawRC(FIFOLevelReg);
              	lastBits = ReadRawRC(ControlReg) & 0x07;
                if (lastBits)
                {   
					*pOutLenBit = (n-1)*8 + lastBits;   
				}
                else
                {   
					*pOutLenBit = n*8;   
				}
                if (n == 0)
                {   
					n = 1;    
				}
                if (n > MAXRLEN)
                {   
					n = MAXRLEN;   
				}
                for (i=0; i<n; i++)
                {   
					pOutData[i] = ReadRawRC(FIFODataReg);    
				}
            }
        }
        else
        {   
			status = MI_ERR;   
		}
        
    }
   
    SetBitMask(ControlReg,0x80);           // stop timer now
    WriteRawRC(CommandReg,PCD_IDLE); 
    return status;
}
//==================================================================================================
//| 函数名称 | PcdRequest
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 寻卡  函数
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | req_code[IN]:寻卡方式 0x52 = 寻感应区内所有符合14443A标准的卡 0x26 = 寻未进入休眠状态的卡
//|          | pTagType[OUT]：卡片类型代码 0x4400 = Mifare_UltraLight 0x0400 = Mifare_One(S50) 
//|          | 0x0200 = Mifare_One(S70) 0x0800 = Mifare_Pro(X) 0x4403 = Mifare_DESFire
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
char PcdRequest(unsigned char req_code,unsigned char *pTagType)
{
   signed char status;  
   unsigned int  unLen;
   unsigned char ucComMF522Buf[MAXRLEN]; 
   ClearBitMask(Status2Reg,0x08);
   WriteRawRC(BitFramingReg,0x07);

   SetBitMask(TxControlReg,0x03);
 
   ucComMF522Buf[0] = req_code;

   status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);

   if ((status == MI_OK) && (unLen == 0x10))
   {    
       *pTagType     = ucComMF522Buf[0];
       *(pTagType+1) = ucComMF522Buf[1];
   }
   else
   {   status = MI_ERR;   }
   
   return status;
}
//==================================================================================================
//| 函数名称 | PcdAnticoll
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 防冲撞  函数
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | pSnr[OUT]:卡片序列号，4字节
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
signed char PcdAnticoll(unsigned char *pSnr)
{
    signed char status;
    unsigned char i,snr_check=0;
    unsigned int  unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    

    ClearBitMask(Status2Reg,0x08);
    WriteRawRC(BitFramingReg,0x00);
    ClearBitMask(CollReg,0x80);
 
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x20;

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);

    if (status == MI_OK)
    {
    	 for (i=0; i<4; i++)
         {   
             *(pSnr+i)  = ucComMF522Buf[i];
             snr_check ^= ucComMF522Buf[i];
         }
         if (snr_check != ucComMF522Buf[i])
         {   status = MI_ERR;    }
    }
    
    SetBitMask(CollReg,0x80);
    return status;
}
//==================================================================================================
//| 函数名称 | PcdSelect
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 选定卡片
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | pSnr[IN]:卡片序列号，4字节
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
signed char PcdSelect(unsigned char *pSnr)
{
    signed char status;
    unsigned char i;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x70;
    ucComMF522Buf[6] = 0;
    for (i=0; i<4; i++)
    {
    	ucComMF522Buf[i+2] = *(pSnr+i);
    	ucComMF522Buf[6]  ^= *(pSnr+i);
    }
    CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
  
    ClearBitMask(Status2Reg,0x08);

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    
    if ((status == MI_OK) && (unLen == 0x18))
    {   
		status = MI_OK;  
	}
    else
    {   
		status = MI_ERR;    
	}

    return status;
} 
//==================================================================================================
//| 函数名称  | PcdAuthState
//|----------|--------------------------------------------------------------------------------------
//| 函数功能  | 验证卡片密码
//|----------|--------------------------------------------------------------------------------------
//| 输入参数  | auth_mode[IN]: 密码验证模式  0x60 = 验证A密钥 0x61 = 验证B密钥 
//|          | addr[IN]：块地址  pKey[IN]：密码 pSnr[IN]：卡片序列号，4字节
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数  | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计  | zb
//==================================================================================================
signed char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr)
{
    signed char status;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = auth_mode;
    ucComMF522Buf[1] = addr;
	memcpy(&ucComMF522Buf[2], pKey, 6); 
	memcpy(&ucComMF522Buf[8], pSnr, 6); 
    
    status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
    {   
		status = MI_ERR;   
	}
    
    return status;
}
//==================================================================================================
//| 函数名称  | PcdRead
//|----------|--------------------------------------------------------------------------------------
//| 函数功能  | 读取M1卡一块数据
//|----------|--------------------------------------------------------------------------------------
//| 输入参数  | addr[IN]：块地址
//|          |  pData[OUT]：读出的数据，16字节
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数  | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计  | zb
//==================================================================================================
signed char PcdRead(unsigned char addr,unsigned char *pData)
{
    signed char status;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = PICC_READ;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
   
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status == MI_OK) && (unLen == 0x90))
   	{   
		memcpy(pData, ucComMF522Buf, 16);   
	}
    else
    {   
		status = MI_ERR;   
	}
    
    return status;
}
//==================================================================================================
//| 函数名称 | PcdWrite
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 写数据到M1卡一块
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | addr[IN]：块地址    pData[IN]：写入的数据，16字节
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
signed char PcdWrite(unsigned char addr,unsigned char *pData)
{
    signed char status;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_WRITE;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   
		status = MI_ERR;   
	}
        
    if (status == MI_OK)
    {
        memcpy(ucComMF522Buf, pData, 16);
        CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);

        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
        if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
        {   
			status = MI_ERR;   
		}
    }
    
    return status;
}
//==================================================================================================
//| 函数名称 | PcdHalt
//|----------|--------------------------------------------------------------------------------------
//| 函数功能 | 命令卡片进入休眠状态
//|----------|--------------------------------------------------------------------------------------
//| 输入参数 | 
//|----------|--------------------------------------------------------------------------------------       
//| 返回参数 | 
//|----------|-------------------------------------------------------------------------------------- 
//| 函数设计 | zb
//==================================================================================================
signed char PcdHalt(void)
{
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = PICC_HALT;
    ucComMF522Buf[1] = 0;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    return MI_OK;
}
uint8_t ReadRfCard(uint8_t *pdata,uint8_t sector,uint8_t block)
{
   uint8_t temp[50];
   uint8_t key[6]={0xff,0xff,0xff,0xff,0xff,0xff};
   uint8_t g_cSNR[4];
   //寻卡
   if(PcdRequest(0x52,temp) != MI_OK)
   {
	   return PICCERR_NOCARD;
   }
   //防冲突
   if(PcdAnticoll(g_cSNR) != MI_OK)
   {
	   return PICCERR_ANTI;
   }
   //选卡
   if(PcdSelect(g_cSNR) != MI_OK)
   {
	   return PICCERR_SELECT;
   }
   //校验密码
   if(PcdAuthState(0x60,sector*4+block,key,g_cSNR) != MI_OK)
   {
	   return PICCERR_PSW;
   }
   //读块取数据
   if(PcdRead(sector*4+block,temp) == MI_OK)
   {
	   memcpy(pdata,temp,16);
	   pdata[16] = 0;
   }
   else
   {
	   return PICCERR_DATA;
   }
   //休眠
   PcdHalt();

   return PICCERR_NULL;
}
uint8_t DecodeRf(uint8_t *pdata,uint32_t *id,uint8_t *name)
{
    	uint8_t temp[5]={0};

	temp[0] = pdata[3];
	temp[1] = pdata[2];
	temp[2] = pdata[1];
	temp[3] = pdata[0];

	*id = *(uint32_t*)temp;
	memcpy(name,pdata+6,10);
	return 1;
}
void BeepInit(void)
{
	uint32_t i,j;
	FILE *fp;
	char str[256];

	if ((fp = fopen("/sys/class/gpio/export", "w")) == NULL) 
	{
		printf("Cannot open export file.\n");
		return;
	}
	fprintf(fp, "%d", beep_ionum);
	fclose(fp);

	sprintf(str,"/sys/class/gpio/gpio%d/direction",beep_ionum);
	if ((fp = fopen(str, "rb+")) == NULL) 
	{
		printf("Cannot open direction file.\n");
		return;
	}
	fprintf(fp, "out");
	fclose(fp);
}
void Beep(uint32_t time)
{
	uint32_t i,j;
	FILE *fp;
	char str[256];
	char buf[10];

	sprintf(str,"/sys/class/gpio/gpio%d/value",beep_ionum);
	if ((fp = fopen(str, "rb+")) == NULL) 
	{
		printf("Cannot open value file.\n");
		return;
	} 
	strcpy(buf,"1");  
	fwrite(buf, sizeof(char), sizeof(buf) - 1, fp);  
	fclose(fp);

	usleep(time*1000);
	if ((fp = fopen(str, "rb+")) == NULL) 
	{
		printf("Cannot open value file.\n");
		return;
	} 
	strcpy(buf,"0");  
	fwrite(buf, sizeof(char), sizeof(buf) - 1, fp);  
	fclose(fp);
}
int main(int argc, char *argv[])
{
	uint8_t temp[50];
	int ret = 0;
	uint8_t rfbuf[50],res;
   	uint32_t ul_wknum;
	uint8_t uch_name[10];
	char strtemp[50];
	uint8_t flag=0;
	
	BeepInit();
	mode  |= SPI_CPOL;
	//mode  |= SPI_CPHA;
	speed = 400000;

	fd = open(device, O_RDWR);
	if (fd < 0)
		pabort("can't open device");

	

	/*
	 * bits per word
	 */
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	/*
	 * max speed hz
	 */
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");

	/*
	 * spi mode
	 */
	//ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	//if (ret == -1)
	//	pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	//printf("spi mode: %d\n", mode);
	//printf("bits per word: %d\n", bits);
	//printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

	//transfer(fd);
	PcdReset();
	PcdAntennaOff(); 
	PcdAntennaOn();  
	M500PcdConfigISOType( 'A' );

	//net
	int socket_descriptor; //套接口描述字  
	int iter=0;  
	struct sockaddr_in address;//处理网络通信的地址

	memset(&address,0,sizeof(address));  
	address.sin_family=AF_INET;  
	address.sin_addr.s_addr=inet_addr("127.0.0.1");//本机
	address.sin_port=htons(8001);  
	socket_descriptor=socket(PF_INET,SOCK_DGRAM,0);

	while(1)
	{
		ret = ReadRfCard(rfbuf,2,0);
		if(ret == PICCERR_NULL)
		{
			if(flag == 0)
			{
				flag = 1;
				Beep(200);
				DecodeRf(rfbuf,&ul_wknum,uch_name);
				//sprintf(strtemp,"Name:%s\n",uch_name);
				//printf(strtemp);
				sendto(socket_descriptor,uch_name,sizeof(uch_name),0,(struct sockaddr *)&address,sizeof(address));
			}
		}
		else
		{
			flag = 0;
		}
		usleep(500000);
	}
	close(fd);

	return ret;
}
